package org.proteored.miapeapi.xml.pride.ms;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.log4j.Logger;
import org.proteored.miapeapi.cv.Accession;
import org.proteored.miapeapi.cv.ControlVocabularyManager;
import org.proteored.miapeapi.cv.SampleInformation;
import org.proteored.miapeapi.cv.msi.PrideProject;
import org.proteored.miapeapi.exceptions.IllegalMiapeArgumentException;
import org.proteored.miapeapi.exceptions.MiapeDatabaseException;
import org.proteored.miapeapi.exceptions.MiapeSecurityException;
import org.proteored.miapeapi.interfaces.User;
import org.proteored.miapeapi.interfaces.ms.Acquisition;
import org.proteored.miapeapi.interfaces.ms.DataAnalysis;
import org.proteored.miapeapi.interfaces.ms.InstrumentConfiguration;
import org.proteored.miapeapi.interfaces.ms.MSAdditionalInformation;
import org.proteored.miapeapi.interfaces.ms.MiapeMSDocument;
import org.proteored.miapeapi.interfaces.ms.ResultingData;
import org.proteored.miapeapi.interfaces.ms.Spectrometer;
import org.proteored.miapeapi.interfaces.persistence.PersistenceManager;
import org.proteored.miapeapi.interfaces.xml.MiapeXmlFile;
import org.proteored.miapeapi.interfaces.xml.XmlMiapeFactory;
import org.proteored.miapeapi.validation.ValidationReport;
import org.proteored.miapeapi.validation.ms.MiapeMSValidator;
import org.proteored.miapeapi.xml.ms.MiapeMSXmlFactory;
import org.proteored.miapeapi.xml.pride.AbstractDocumentFromPride;
import org.proteored.miapeapi.xml.pride.autogenerated.CvParamType;
import org.proteored.miapeapi.xml.pride.autogenerated.DescriptionType;
import org.proteored.miapeapi.xml.pride.autogenerated.ExperimentType;
import org.proteored.miapeapi.xml.pride.autogenerated.InstrumentDescriptionType.AnalyzerList;
import org.proteored.miapeapi.xml.pride.autogenerated.ParamType;
import org.proteored.miapeapi.xml.pride.autogenerated.SourceFileType;
import org.proteored.miapeapi.xml.pride.autogenerated.UserParamType;
import org.proteored.miapeapi.xml.pride.util.Parameter;
import org.proteored.miapeapi.xml.pride.util.Utils;
import org.proteored.miapeapi.xml.util.MiapeXmlUtil;

public class MiapeMSDocumentImpl extends AbstractDocumentFromPride implements
		MiapeMSDocument {
	protected final XmlMiapeFactory<MiapeMSDocument> xmlFactory;
	private final List<InstrumentConfiguration> instrumentConfigurations = new ArrayList<InstrumentConfiguration>();;
	private static Logger log = Logger.getLogger("log4j.logger.org.proteored");

	public MiapeMSDocumentImpl(ExperimentType experiment, User user,
			String prideXMLFileName, String projectName,
			ControlVocabularyManager cvManager)
			throws IllegalMiapeArgumentException {
		super(experiment, cvManager, user, prideXMLFileName, projectName);
		instrumentConfigurations.add(new InstrumentConfigurationImpl(
				instrumentManager));
		xmlFactory = MiapeMSXmlFactory.getFactory();

	}

	public MiapeMSDocumentImpl(ExperimentType experiment,
			PersistenceManager dbManager, ControlVocabularyManager cvManager,
			String user, String password, String prideXMLFileName,
			String projectName) throws MiapeDatabaseException,
			MiapeSecurityException, IllegalMiapeArgumentException {
		super(experiment, dbManager, cvManager, user, password,
				prideXMLFileName, projectName);
		instrumentConfigurations.add(new InstrumentConfigurationImpl(
				instrumentManager));
		xmlFactory = MiapeMSXmlFactory.getFactory();

	}

	public void setDatabaseManager(PersistenceManager dbManager) {
		this.dbManager = dbManager;
	}

	@Override
	public Set<Acquisition> getAcquisitions() {
		log.info("getAcquisitions");
		Set<Acquisition> acquisitions = new HashSet<Acquisition>();
		if (experiment.getMzData() != null
				&& experiment.getMzData().getDescription() != null
				&& experiment.getMzData().getDescription().getDataProcessing() != null
				&& experiment.getMzData().getDescription().getDataProcessing()
						.getSoftware() != null) {
			Integer softwareID = MiapeXmlUtil.SoftwareCounter.increaseCounter();
			AnalyzerList analyzers = null;
			if (experiment.getMzData() != null
					&& experiment.getMzData().getDescription() != null
					&& experiment.getMzData().getDescription().getInstrument() != null
					&& experiment.getMzData().getDescription().getInstrument()
							.getAnalyzerList() != null)
				analyzers = experiment.getMzData().getDescription()
						.getInstrument().getAnalyzerList();
			acquisitions.add(new AcquisitionImpl(experiment.getMzData()
					.getDescription().getDataProcessing().getSoftware(),
					analyzers, softwareID, cvManager));
		}
		return acquisitions;
	}

	@Override
	public Set<DataAnalysis> getDataAnalysis() {
		log.info("get dataanalysis");
		if (experiment.getMzData() != null
				&& experiment.getMzData().getDescription() != null
				&& experiment.getMzData().getDescription().getDataProcessing() != null
				&& experiment.getMzData().getDescription().getDataProcessing()
						.getProcessingMethod() != null) {
			Set<DataAnalysis> dataAnalysis = new DataAnalysisManager(experiment
					.getMzData().getDescription().getDataProcessing()
					.getProcessingMethod(), cvManager).getDataAnalysis();
			if (dataAnalysis != null)
				return dataAnalysis;
		}
		return null;
	}

	/*
	 * @Override public Set<Quantitation> getQuantitations() { // TODO
	 * Auto-generated method stub return null; }
	 */

	@Override
	public List<ResultingData> getResultingDatas() {
		log.info("get resulting datas");
		if (experiment != null && experiment.getMzData() != null
				&& experiment.getMzData().getDescription() != null
				&& experiment.getMzData().getDescription().getAdmin() != null) {
			final SourceFileType sourceFile = experiment.getMzData()
					.getDescription().getAdmin().getSourceFile();
			if (sourceFile != null) {
				List<ResultingData> resultingDatas = new ArrayList<ResultingData>();

				resultingDatas.add(new ResultingDataImpl(sourceFile));

				return resultingDatas;
			}
		}
		return null;
	}

	@Override
	public Set<Spectrometer> getSpectrometers() {
		log.info("get spectrometers");
		Set<Spectrometer> resultSet = new HashSet<Spectrometer>();
		if (instrumentManager.getSpectrometer() != null) {
			resultSet.add(instrumentManager.getSpectrometer());
		}
		return resultSet;
	}

	@Override
	public int store() throws MiapeDatabaseException, MiapeSecurityException {
		log.info("store miape ms");
		if (dbManager != null
				&& dbManager.getMiapeMSPersistenceManager() != null) {
			return dbManager.getMiapeMSPersistenceManager().store(this);
		}
		throw new MiapeDatabaseException(
				"The persistance method is not defined.");
	}

	@Override
	public void delete(String user, String password)
			throws MiapeDatabaseException, MiapeSecurityException {
		log.info("delete miape ms");
		if (dbManager != null
				&& dbManager.getMiapeMSPersistenceManager() != null) {
			dbManager.getMiapeMSPersistenceManager().deleteById(getId(), user,
					password);
		}
		throw new MiapeDatabaseException(
				"The persistance method is not defined.");
	}

	@Override
	public MiapeXmlFile<MiapeMSDocument> toXml() {
		log.info("to xml miape ms");
		if (xmlFactory != null) {
			return xmlFactory.toXml(this, cvManager);
		}
		return null;
	}

	@Override
	public List<MSAdditionalInformation> getAdditionalInformations() {
		log.info("get add info");
		List<MSAdditionalInformation> setOfAdditionalInformations = new ArrayList<MSAdditionalInformation>();

		if (experiment.getProtocol() != null) {

			if (experiment.getProtocol().getProtocolName() != null) {
				setOfAdditionalInformations.add(new AdditionalInformationImpl(
						"Protocol name", experiment.getProtocol()
								.getProtocolName()));
			}

			if (experiment.getProtocol().getProtocolSteps() != null) {
				for (ParamType paramType : experiment.getProtocol()
						.getProtocolSteps().getStepDescription()) {
					List<Parameter> listParameter = Utils.createListParameter(
							paramType.getCvParamOrUserParam(), null);
					if (listParameter != null)
						for (Parameter param : listParameter) {
							setOfAdditionalInformations
									.add(new AdditionalInformationImpl(param
											.getName(), param.getValue()));
						}
				}
			}
			if (experiment.getTitle() != null)
				setOfAdditionalInformations.add(new AdditionalInformationImpl(
						"PRIDE title", experiment.getTitle()));
			if (experiment.getShortLabel() != null)
				setOfAdditionalInformations.add(new AdditionalInformationImpl(
						"PRIDE short label", experiment.getShortLabel()));

			if (experiment.getMzData() != null
					&& experiment.getMzData().getDescription() != null
					&& experiment.getMzData().getDescription().getAdmin() != null
					&& experiment.getMzData().getDescription().getAdmin() != null) {
				// sample name
				String sampleName = experiment.getMzData().getDescription()
						.getAdmin().getSampleName();
				if (sampleName != null) {
					final String sampleBatchCVName = cvManager
							.getControlVocabularyName(
									SampleInformation.SAMPLE_BATCH_ACC,
									SampleInformation.getInstance(cvManager));
					CvParamType cvParam = new CvParamType();
					cvParam.setAccession(SampleInformation.SAMPLE_BATCH_ACC
							.toString());
					cvParam.setName(sampleBatchCVName);
					cvParam.setValue(sampleName);
					setOfAdditionalInformations
							.add(new AdditionalInformationImpl(cvParam));
				}
				// sample description
				final DescriptionType sampleDescription = experiment
						.getMzData().getDescription().getAdmin()
						.getSampleDescription();
				if (sampleDescription != null
						&& sampleDescription.getCvParamOrUserParam() != null) {
					for (Object cvOrUserParam : sampleDescription
							.getCvParamOrUserParam()) {
						if (cvOrUserParam instanceof CvParamType)
							setOfAdditionalInformations
									.add(new AdditionalInformationImpl(
											(CvParamType) cvOrUserParam));
						if (cvOrUserParam instanceof UserParamType)
							setOfAdditionalInformations
									.add(new AdditionalInformationImpl(
											(UserParamType) cvOrUserParam));
					}

				}
			}
		}
		if (!setOfAdditionalInformations.isEmpty())
			return setOfAdditionalInformations;

		return null;
	}

	@Override
	public ValidationReport getValidationReport() {
		return MiapeMSValidator.getInstance().getReport(this);
	}

	@Override
	public String getName() {
		log.info("get name");
		// Try to obtain the name of the CV=PRIDE:0000097 -> project
		if (experiment.getAdditional() != null) {
			for (Object cvOrUserParam : experiment.getAdditional()
					.getCvParamOrUserParam()) {
				if (cvOrUserParam instanceof CvParamType) {
					final Accession cvAcc = cvManager.getControlVocabularyId(
							((CvParamType) cvOrUserParam).getName(),
							PrideProject.getInstance(cvManager));
					if (cvAcc != null)
						return ((CvParamType) cvOrUserParam).getValue();
				} else if (cvOrUserParam instanceof UserParamType) {
					final Accession cvAcc = cvManager.getControlVocabularyId(
							((UserParamType) cvOrUserParam).getName(),
							PrideProject.getInstance(cvManager));
					if (cvAcc != null)
						return ((UserParamType) cvOrUserParam).getValue();
				}
			}
		}
		// if not, return a default name
		return "MIAPE MS from PRIDE file";
	}

	@Override
	public List<InstrumentConfiguration> getInstrumentConfigurations() {
		if (!instrumentConfigurations.isEmpty())
			return instrumentConfigurations;

		return null;
	}

}
